<?php

namespace App\Kuafu\Order\Controller\Applet;

use App\Kuafu\Base\Controller\BaseController;
use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\Common\Service\CommonService;
use App\Kuafu\CouponPackage\Model\CouponPackageModel;
use App\Kuafu\CouponPackage\Model\CouponPackageOrderModel;
use App\Kuafu\CouponPackage\Service\CouponPackageService;
use App\Kuafu\Customer\Model\CustomerPlatformModel;
use App\Kuafu\Customer\Service\CustomerPlatformService;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Enum\OrderCacheEnum;
use App\Kuafu\Order\Enum\OrderCodeEnum;
use App\Kuafu\Order\Exceptions\OrderException;
use App\Kuafu\Order\Jobs\PayOrderJob;
use App\Kuafu\Order\Model\OrderExternalSplitModel;
use App\Kuafu\Order\Service\ConsumerOrderService;
use App\Kuafu\Order\Service\OrderHandleService;
use App\Kuafu\Order\Service\OrderPay;
use App\Kuafu\Order\Service\OrderPayService;
use App\Kuafu\Order\Service\OrderService;
use App\Kuafu\Order\Service\OrderUserService;
use App\Kuafu\Pay\Exceptions\PayException;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Service\PayService;
use App\Kuafu\User\Exceptions\UserException;
use App\Kuafu\Wechat\Exceptions\WechatException;
use App\Kuafu\Wechat\Service\WechatService;
use App\Support\AppletEncrypt;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class OrderController extends BaseController
{
    /**
     * 预 - 计算
     * @param Request $request
     * @return JsonResponse
     * @throws OrderException
     */
    public function preCalc(Request $request): JsonResponse
    {
        $data               = $request->all();
        $data['sourceType'] = CodeEnum::SOURCE_TYPE_MINI;
        $postData           = OrderService::getOrderFormatPostData($data);
        // 手动关闭自配送限制
        $postData['isSelfDelivery'] = BaseModel::SWITCH_OFF;
//        $postData['deliveryType']   = BaseModel::SWITCH_OFF;

        $order = new OrderHandleService($this->brandId, $this->shopId);

        $order->setUserId($request);

        $order->calcPrice($postData);

        $couponList  = $order->getUserUsedCoupon() + $order->getPosUsedCoupon();
        $resultOrder = $order->getOrderPrice() + ['couponList' => $couponList];

        $preCouponList = $order->getUserCoupon();
        return $this->success(
            [
                'order'             => $resultOrder,
                'couponList'        => $preCouponList['user'],
                'couponPackageList' => $preCouponList['couponPackage'],
                'orderDetail'       => $order->getOrderCalc()->getOrderFilterOrderDetail()
            ]
        );
    }

    public function getUserOrderList(Request $request): JsonResponse
    {
        $userId       = CustomerPlatformService::getUserId($request);
        $pageSize     = (int)$request->pageSize ?: 10;
        $pageNum      = (int)$request->pageNum ?: 1;
        $flagComplain = (int)$request->flagComplain ?: CodeEnum::ORDER_STATUS_DEFAULT;//默认不传 1-小程序投诉（获取支付完成的订单，最近10条）
        if ($flagComplain == 1) {
            $pageSize = 10;
            $pageNum  = 1;
        }
        //获取订单列表以及详情
        $userOrderList = OrderService::getUserOrderList($userId, $pageSize, $pageNum, $this->shopId, $flagComplain);
        return $this->success($userOrderList);
    }

    public function getUserOrderListAll(Request $request): JsonResponse
    {
        $userId   = CustomerPlatformService::getUserId($request);
        $pageSize = (int)$request->pageSize ?: 10;
        $pageNum  = (int)$request->pageNum ?: 1;

        $appletToken = $request->header('APPLET-TOKEN');
        $platformId  = $request->header('platformId');

        list($userOpenId, $userUnionid) = OrderUserService::getCreateOrderUserOpenId($appletToken, $platformId);

        $flagComplain = (int)$request->flagComplain ?: CodeEnum::ORDER_STATUS_DEFAULT;//默认不传 1-小程序投诉（获取支付完成的订单，最近10条）
        if ($flagComplain == 1 && $userId) {
            $pageSize = 10;
            $pageNum  = 1;
        }
        //获取订单列表以及详情
        $userOrderList = ConsumerOrderService::getUserAllOrderList($userId, $userUnionid, $pageSize, $pageNum,
            $this->shopId,
            $flagComplain);
        return $this->success($userOrderList);
    }

    /**
     * 获取用户订单详情
     * @param Request $request
     * @return JsonResponse
     */
    public function getOrderInfo(Request $request)
    {
        $orderId     = (string)$request->orderId;
        $userId      = CustomerPlatformService::getUserId($request);
        $orderFiled  = [
            'orderStatus',
            'payPrice',
            'shouldPrice',
            'discountPrice',
            'createdAt',
            'orderId',
            'remark',
            'originalPrice',
            'serialNum',
            'couponPrice',
            'payStatus',
            'isSelfDelivery',
            'distributionId',
            'deliveryType',
//            'distributionPer',
//            'distributionAmount',
            'orderShouldPrice',
            'realPayPrice',
        ];
        $couponField = ['id', 'orderId', 'couponName'];
        $detailField = [
            'productName',
            'id',
            'orderId',
            'productId',
            'num',
            'originalUnitPrice',
            'unit',
            'imageUrl',
            'packageDetailId',
            'type',
            'packageUnitNum',
            'freeNum'
        ];
        $orderInfo   = OrderService::getUserOrderDetailByOrderId($this->shopId, $userId, $orderId, $orderFiled,
            $detailField, $couponField);

        if (empty($orderInfo)) {
            return $this->fail(OrderCodeEnum::ERR_ORDER_ID_NOT_EXIST,
                OrderCodeEnum::CODE_TEXT[OrderCodeEnum::ERR_ORDER_ID_NOT_EXIST]);
        }
        $detailRel = $orderInfo['orderDetailRel'];
        //todo 查询订单使用的优惠券信息
        //组装数据
        foreach ($detailRel as $k => $value) {
            $detailRel[$k]['imageUrl'] = CommonService::joinImageUrl($value['imageUrl']);
        }

        //判断是否有购买券包信息
        $orderInfo->couponPackage = null;
        if ($orderInfo->orderExtRel && $orderInfo->orderExtRel->where('type', '=',
                CodeEnum::ORDER_EXTERNAL_TYPE_COUPON_PACKAGE)->count() > 0) {
            if (($extOrderId = $orderInfo->orderExtRel->where('type',
                    '=', CodeEnum::ORDER_EXTERNAL_TYPE_COUPON_PACKAGE)->first()->extOrderId) > 0) {
                $couponPackageOrder       = CouponPackageService::getOrderDetailByOrderId($extOrderId);
                $orderInfo->couponPackage = [
                    'name'  => $couponPackageOrder->couponPackageRel->name,
                    'price' => $couponPackageOrder->couponPackageRel->salePrice
                ];
            }
        }

        $orderInfo = OrderService::orderDetailDataToChange($orderInfo);
        return $this->success($orderInfo);
    }

    /**
     * 下单
     * @param $request
     * @return JsonResponse
     * @throws OrderException
     * @throws UserException
     * @throws PayException
     */
    public function createOrder(Request $request): JsonResponse
    {
        $data               = $request->all();
        $data['sourceType'] = CodeEnum::SOURCE_TYPE_MINI;
        $postData           = OrderService::getOrderFormatPostData($data);

        $order = new OrderHandleService($this->brandId, $this->shopId);

        // 设置 userID
        $order->setUserId($request);

        // 没授权手机号, 购买券包提示异常
        if (!$order->getUserId() && !empty($data['couponPackageId'])) {
            throw new OrderException(OrderCodeEnum::ERR_ORDER_ADD_ERROR, '券包购买需授权手机号，防止券信息丢失。');
        }

        // 校验是否绑定富友支付
        $orderPay = new OrderPay($this->brandId, $this->shopId);
        $orderPay->checkBindFuYou();

        // 计价
        $order->calcPrice($postData);

        // 生成订单
        $order->handleOrder($postData);

        // 支付订单
        $orderPay = new OrderPay($this->brandId, $this->shopId, $order->getOrderId());

        // 平台设置
        $platformId = $request->header('platformId');

        // 仅为了做测试用
        if ((config('app.env') != 'prod' && $request->get('debugPay') == 1)) {
            $orderPay    = new OrderPay($this->brandId, $this->shopId, $order->getOrderId());
            $appletToken = $request->header('APPLET-TOKEN');
            list($userOpenId, $unionid) = OrderUserService::getCreateOrderUserOpenId($appletToken, $platformId);

            // 设置支付用户信息配置
            $orderPay->setUserInfo([
                'userId'     => $order->getUserId(),
                'openId'     => $userOpenId,
                'platformId' => $platformId,
                'unionid'    => $unionid
            ]);

            $orderPay->setPayData([
                'payMethod' => CodeEnum::ORDER_PAY_CHANNEL_MONEY,
                'payEvent'  => CodeEnum::ORDER_PAY_EVENT_ORDER
            ]);
            $result = $orderPay->cashPay();
            $orderPay->successV2();
            $orderPay->finish();
            $orderPay->updateOrderPayInfo();
        } else {

            // 设置支付信息配置
            $orderPay->setPayData([
                'payMethod' => CodeEnum::ORDER_PAY_CHANNEL_WECHAT_MINI,
                'payEvent'  => CodeEnum::ORDER_PAY_EVENT_ORDER,
            ]);

            $appletToken = $request->header('APPLET-TOKEN');
            list($userOpenId, $unionid) = OrderUserService::getCreateOrderUserOpenId($appletToken, $platformId);

            // 设置支付用户信息配置
            $orderPay->setUserInfo([
                'userId'     => $order->getUserId(),
                'openId'     => $userOpenId,
                'platformId' => $platformId,
                'unionid'    => $unionid
            ]);

            $result = $orderPay->genAppletPay();
            $orderPay->updateOrderPayInfo();

        }

        $returnData = [
            'payConfig' => $result['payConfig'] ?? [],
            'orderId'   => $order->getOrderId()
        ];

        return $this->success($returnData);
    }

    /**
     * 订单支付
     *
     * @param Request $request
     * @return JsonResponse
     * @throws OrderException
     * @throws \App\Exceptions\BaseException
     */
    public function payOrder(Request $request)
    {
        $userId      = CustomerPlatformService::getUserId($request);
        $platformId  = $request->header('platformId');
        $appletToken = $request->header('APPLET-TOKEN');

        $data = $request->all();

        $data['sourceType'] = CodeEnum::SOURCE_TYPE_MINI;

        $orderId = $request->orderId;

        $order     = new OrderHandleService(0, $this->shopId, $orderId);
        $orderInfo = $order->getOrderInfo();

        if (empty($orderInfo)) {
            throw new OrderException(OrderCodeEnum::ERR_ORDER_DB_ADD, "订单不存在");
        }

        // 支付订单
        $orderPay = new OrderPay($orderInfo->brandId, $orderInfo->shopId, $orderId);

//        $unionid     = AppletEncrypt::getInstance()->getUserUnionid($appletToken);
//        $customer    = CustomerPlatformModel::query()->where('unionid', $unionid)->first();
//        if (empty($userId) || $userId == 0) {
//            $userOpenId = $customer->openId;
//        } else {
//            $userOpenId = CustomerPlatformService::getUserFieldByUserId($userId, $platformId, ['openid'])->openid ?? '';
//        }

        list($userOpenId, $unionid) = OrderUserService::getCreateOrderUserOpenId($appletToken, $platformId);

        // 设置支付信息配置
        $orderPay->setPayData([
            'payMethod' => CodeEnum::ORDER_PAY_CHANNEL_WECHAT_MINI,
            'payEvent'  => CodeEnum::ORDER_PAY_EVENT_ORDER,
        ]);

        // 设置支付用户信息配置
        $orderPay->setUserInfo([
            'userId'     => $userId,
            'openId'     => $userOpenId,
            'platformId' => $platformId,
            'unionid'    => $unionid
        ]);


        $result = $orderPay->genAppletPay();
        $orderPay->updateOrderPayInfo();

        $returnData = [
            'payConfig' => $result['payConfig'] ?? [],
            'orderId'   => $orderId
        ];

        return $this->success($returnData);
    }

    /**
     * 生成pos订单详情小程序菊花码
     * @param Request $request
     * @return JsonResponse
     * @throws WechatException
     * @throws GuzzleException
     */
    public function createOrderQrCode(Request $request): JsonResponse
    {
        $orderId = (int)$request->orderId;
        $shopId  = $this->shopId;
        //订单号生成加密token且只能使用一次
        $token = AppletEncrypt::getInstance()->encryptOrderData($orderId, CodeEnum::QR_CODE_KEY);
        //生成token保存到redis
        Redis::setex(OrderCacheEnum::PREFIX_ORDER_TOKEN . $orderId, CodeEnum::QR_CODE_EXPIRE_TIME, $token);
        $path   = config('wechat.orderInfoPage') . "?orderToken=$token";
        $data   = array("path" => $path, "width" => 150);
        $qrCode = WechatService::createQrCode(CodeEnum::QR_CODE_ONE, $data, $shopId);
        return $this->success(['image' => $qrCode]);
    }

    public function getOrderDetailByQrCode(Request $request)
    {
        $token = $request->orderToken;
        if (!$token) {
            return $this->fail(OrderCodeEnum::ERR_NO_TOKEN);
        }
        $decrypt = AppletEncrypt::getInstance()->decryptShort($token, CodeEnum::QR_CODE_KEY);
        $decrypt = json_decode($decrypt, true);
        if (!is_array($decrypt) || !isset($decrypt['orderId'])) {
            return $this->fail(OrderCodeEnum::ERR_ORDER_TOKEN_DECRYPT);
        }
        $orderId = (string)$decrypt['orderId'];
        //检查redis是否存在该笔订单token
        if (!Redis::get(OrderCacheEnum::PREFIX_ORDER_TOKEN . $orderId)) {
            return $this->fail(OrderCodeEnum::ERR_EXPIRE_TOKEN);
        }
        //删除redis
        Redis::del(OrderCacheEnum::PREFIX_ORDER_TOKEN . $orderId);
        //获取订单信息
        $orderFiled  = [
            'orderStatus',
            'payPrice',
            'shouldPrice',
            'discountPrice',
            'createdAt',
            'orderId',
            'remark',
            'originalPrice',
            'serialNum',
            'shopId',
            'orderShouldPrice',
            'realPayPrice'
        ];
        $couponField = ['id', 'orderId', 'couponName'];
        $userId      = 0;
        $shopId      = $this->shopId;
        $detailField = [
            'productName',
            'id',
            'orderId',
            'productId',
            'num',
            'originalUnitPrice',
            'unit',
            'imageUrl',
            'packageDetailId',
            'packageUnitNum',
            'type'
        ];
        $orderInfo   = OrderService::getUserOrderDetailByOrderId($shopId, $userId, $orderId, $orderFiled, $detailField,
            $couponField);
        if (empty($orderInfo)) {
            return $this->fail(OrderCodeEnum::ERR_ORDER_ID_NOT_EXIST);
        }
        $detailRel = $orderInfo['orderDetailRel'];
        //组装数据
        foreach ($detailRel as $k => $value) {
            $detailRel[$k]['imageUrl'] = CommonService::joinImageUrl($value['imageUrl']);
        }
        $orderInfo = OrderService::orderDetailDataToChange($orderInfo);
        return $this->success($orderInfo);
    }

    /**
     * TODO 重定向不管用，小程序没法做到一码多用了
     * 跳转小程序订单详情 - 兼容多种小程序支付
     * @param Request $request
     * @param string $orderId
     * //     * @return RedirectResponse
     * @throws PayException
     */
    public function jumpToMiniOrderDetail(Request $request, string $orderId): RedirectResponse
    {
        $url = OrderService::sJumpToMiniOrderDetail($orderId);
        return redirect()->to($url);
    }

    /**
     * 订单解锁
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function unLockOrderPay(Request $request)
    {
        $orderId = $request->orderId;
        $order   = new OrderHandleService(0, $this->shopId, $orderId);
        $order->unLockOrder(CodeEnum::ORDER_LOCK_TYPE_ORDER_PAY);

        return $this->success();
    }

    /**
     * 取消订单
     *
     * @param string $orderId
     * @return JsonResponse
     * @throws PayException
     */
    public function cancel(string $orderId): JsonResponse
    {
        $orderId = (int)$orderId;
        $order   = new OrderPayService($this->brandId, $this->shopId, $orderId);
        //todo 判断订单当前状态是否已取消
        if (attributeGet($order->getOrderInfo(), "orderStatus", null) == CodeEnum::ORDER_STATUS_CANCEL) {
            return $this->fail(OrderCodeEnum::ERR_ORDER_CANCEL_STATUS);
        }

        $payStreamModel = PayStreamModel::suffix($this->shopId, PayStreamModel::SYS_TYPE_RMS_MEAL)
                                        ->where("orderId", $orderId)
                                        ->first();

        if (empty($payStreamModel)) {
            Log::channel('order')->error('小程序取消订单数据异常', [
                'orderId' => $orderId
            ]);
            return $this->fail(OrderCodeEnum::ERR_ORDER_CALL_PAY);
        }

        // 获取订单情况
        $orderPay = PayService::sQuery($payStreamModel->payNo);

        // 获取是否支付成功
        if ($orderPay->payStatus != PayStreamModel::PAY_STATUS_1) {
            // 判断订单是否存在券包购买记录
            $existsCouponPackageOrder = OrderExternalSplitModel::suffix($this->shopId)->query()
                                                               ->where("type",
                                                                   CodeEnum::ORDER_EXTERNAL_TYPE_COUPON_PACKAGE)
                                                               ->where('orderId', (int)$orderId)
                                                               ->first();

            if ($existsCouponPackageOrder) {
                // 存在券包订单  更新订单状态&释放库存
                $couponPackageOrder = CouponPackageOrderModel::query()
                                                             ->where("orderId", $existsCouponPackageOrder->extOrderId)
                                                             ->first();
                DB::beginTransaction();
                CouponPackageOrderModel::payFail($couponPackageOrder->orderId);
                CouponPackageModel::reIncrStock($couponPackageOrder->couponPackageId);
                DB::commit();
            }

            $order->cancel();
            return $this->success();
        } else {
            return $this->fail(OrderCodeEnum::ERR_ORDER_CANCEL_STATUS);
        }
    }
}
